package com.ease.platform.access.service.impl;

import static com.ease.dao.util.DataAccessObjectUtil.getById;

import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.CompareToBuilder;

import com.ease.common.util.ReflectionUtil;
import com.ease.model.LifecycleModel;
import com.ease.model.Model;
import com.ease.platform.access.callback.AppendSupplierEntityCallback;
import com.ease.platform.access.service.AbstractParameterizedBeanAccessService;
import com.ease.platform.usercontext.util.UserContextThreadLocal;
import com.ease.platform.usercontext.vo.UserContext;

/**
 *
 * @author nathanleewei
 *
 */
public abstract class AbstractParameterizedBeanAccessServiceImpl<T extends Serializable> extends AbstractNamespaceJdbcTemplateAccessServiceImpl implements AbstractParameterizedBeanAccessService {

	protected Class<T> parameterizedBeanClass;

	@SuppressWarnings("unchecked")
	public AbstractParameterizedBeanAccessServiceImpl() {
		parameterizedBeanClass = (Class<T>) getParameterizedBeanClass(this.getClass());
		namespace = this.parameterizedBeanClass.getSimpleName();
		init();
	}

	protected static Class<?> getParameterizedBeanClass(Class<?> clazz) {
		Class<?> genericType = ReflectionUtil.getGenericType(clazz);
		if (Object.class.equals(genericType) && null != clazz.getSuperclass()) {
			return getParameterizedBeanClass(clazz.getSuperclass());
		}
		return genericType;
	}

	protected void createLifecycleAttribute(Model model) {

		if (model instanceof LifecycleModel) {
			UserContext userContext = UserContextThreadLocal.getUserContext();

			if (null != userContext) {
				LifecycleModel lifecycleModel = (LifecycleModel) model;
				lifecycleModel.setCreator(userContext.getOperator());
				lifecycleModel.setCreateTime(userContext.getOperateTime());
			}
			updateLifecycleAttribute(model);
		}
		// return model;
	}

	protected void updateLifecycleAttribute(Model model) {
		if (model instanceof LifecycleModel) {

			UserContext userContext = UserContextThreadLocal.getUserContext();

			if (null != userContext) {
				LifecycleModel lifecycleModel = (LifecycleModel) model;
				if (StringUtils.isEmpty(lifecycleModel.getCreator())) {
					lifecycleModel.setCreator(userContext.getOperator());
				}
				if (lifecycleModel.getCreateTime() == null) {
					lifecycleModel.setCreateTime(userContext.getOperateTime());
				}
				lifecycleModel.setUpdater(userContext.getOperator());
				lifecycleModel.setUpdateTime(userContext.getOperateTime());
			}
		}
		// return model;
	}

	/**
	 *
	 * @param <S>
	 *            supplier entityType
	 * @param models
	 * @param callback
	 * @return
	 */
	protected <C extends Model, S extends Model> List<C> appendSupplierEntity(List<C> models, AppendSupplierEntityCallback<C, S> appendSupplierEntityCallback) {
		if (null != models) {

			long[] supplierEntityIds = new long[models.size()];

			for (int i = 0; i < models.size(); i++) {
				C model = models.get(i);
				supplierEntityIds[i] = appendSupplierEntityCallback.getSupplierEntityId(model);
			}

			List<S> supplierEntities = appendSupplierEntityCallback.findSupplierEntityByIds(supplierEntityIds);

			if (null != supplierEntities) {
				//
				for (C model : models) {
					appendSupplierEntityCallback.setSupplier(model, getById(appendSupplierEntityCallback.getSupplierEntityId(model), supplierEntities));
				}
			}
		}
		return models;
	}

	// TODO
	// public Map<String, Object> appendParamters(Map<String, Object> parameter) {
	// return parameter;
	// }

	/** create */
	public <M extends Model> void beforeCreate(M model) {
		createLifecycleAttribute(model);
	}

	/** update */
	public <M extends Model> void beforeUpdate(M model) {
		updateLifecycleAttribute(model);
	}

	protected <M extends Model> List<M> sortModelsById(List<M> models) {
		if (notEmpty(models)) {
			Collections.sort(models, new Comparator<M>() {
				public int compare(M t1, M t2) {
					CompareToBuilder compareToBuilder = new CompareToBuilder();
					compareToBuilder.append(t1.getId(), t2.getId());
					return compareToBuilder.toComparison();
				}
			});
		}
		return models;
	}

	/**
	 * @return the parameterizedBeanClass
	 */
	public Class<T> getParameterizedBeanClass() {
		return parameterizedBeanClass;
	}

	/**
	 * @param parameterizedBeanClass
	 *            the parameterizedBeanClass to set
	 */
	public void setParameterizedBeanClass(Class<T> parameterizedBeanClass) {
		this.parameterizedBeanClass = parameterizedBeanClass;
	}
}
